/**
 * 唯一且标准的通知机制
 */
class EventBus {
    BROADCAST_IDENT = "broadcast.web"

    constructor() {
      this._events = [];
      this.broadcastChannelSupport = !!window.BroadcastChannel;
      if (!this.broadcastChannelSupport) return;
      this.broadcastChannel = new BroadcastChannel("web_event_channel");
      this.broadcastChannel.onmessage = (event) => {
        if (!event.data || !event.data.eventName || event.data.eventName !== this.BROADCAST_IDENT) return;
        // logger.log('接受广播事件：',event.data.params)
        Promise.resolve().then(() => {
          this._emit.apply(this, [...event.data.params]);
        });
      };
    }

    /**
     * 注册事件和处理函数
     * @param event
     * @param fn
     */
    on(event, fn) {
      if (Array.isArray(event)) {
        for (let i = 0, l = event.length; i < l; i++) {
          this.on(event[i], fn);
        }
      } else {
        // 存在直接push, 不存在创建为空数组再push
        (this._events[event] || (this._events[event] = [])).push(fn);
      }
      // console.log(this._events)
    }

    /**
     * 注册事件和处理函数，触发一次后销毁
     * @param event
     * @param fn
     */
    once(event, fn) {
      const _self = this;
      function handler() {
        _self.off(event, handler);
        fn(...arguments);
      }

      handler.fn = fn;
      this.on(event, handler);
    }

    /**
     * 销毁事件和处理函数
     * @param event
     * @param fn
     */
    off(event, fn) {
      if (!arguments.length) {
        this._events = [];
      }
      // 数组循环清空
      if (Array.isArray(event)) {
        for (let i = 0, l = event.length; i < l; i++) {
          this.off(event[i], fn);
        }
      }
      const cbs = this._events[event];
      if (!cbs) {
        return;
      }
      // 不传第二参表示清空某事件所有监听函数
      if (arguments.length === 1) {
        this._events[event] = null;
      }
      let cb,
        i = cbs.length;
      while (i--) {
        cb = cbs[i];
        if (cb === fn || cb.fn === fn) {
          cbs.splice(i, 1);
          break;
        }
      }
    }

    /**
     * 触发某事件所有回调并带参数
     * @param event
     */
    emit(event) {
      const registor = this._events[event] ? this._events[event] : [];
      const cbs = [...registor];
      // logger.log('外部广播事件：',event,cbs)
      if (cbs) {
        for (let i = 0, l = cbs.length; i < l; i++) {
          try {
            cbs[i].apply(null, [...arguments].slice(1));
            // 广播
            if (this.broadcastChannelSupport && i === 0) {
              this.broadcastChannel.postMessage({ eventName: this.BROADCAST_IDENT, params: [...arguments] });
            }
          } catch (e) {
            throw new Error(e, `event handler for "${event}"`);
          }
        }
      }
    }

    _emit(event) {

      const registor = this._events[event] ? this._events[event] : [];
      const cbs = [...registor];
      if (cbs) {
        for (let i = 0, l = cbs.length; i < l; i++) {
          try {
            cbs[i].apply(null, [...arguments].slice(1));
          } catch (e) {
            throw new Error(e, `event handler for "${event}"`);
          }
        }
      }
    }
}

export const eventBus = new EventBus();
